<?php

namespace plugin\admin\app\common;

use plugin\admin\app\constant\v1\CommonConstant;
use plugin\admin\app\model\Option;
use plugin\admin\app\service\v1\OptionService;
use process\Monitor;
use support\Log;
use Throwable;
use Illuminate\Database\Connection;
use Illuminate\Database\Schema\Builder;
use support\exception\BusinessException;
use support\Db;
use support\Redis;
use Workerman\Timer;
use Workerman\Worker;

class Util
{
    /**
     * 密码哈希
     * @param $password
     * @param string $algo
     * @return false|string|null
     */
    public static function passwordHash($password, string $algo = PASSWORD_DEFAULT)
    {
        return password_hash($password, $algo);
    }

    /**
     * 验证密码哈希
     * @param string $password
     * @param string $hash
     * @return bool
     */
    public static function passwordVerify(string $password, string $hash): bool
    {
        return password_verify($password, $hash);
    }

    /**
     * 获取webman-admin数据库连接
     * @return Connection
     */
    public static function db(): Connection
    {
        return Db::connection('plugin.admin.mysql');
    }

    /**
     * 获取SchemaBuilder
     * @return Builder
     */
    public static function schema(): Builder
    {
        return Db::schema('plugin.admin.mysql');
    }

    /**
     * 获取语义化时间
     * @param $time
     * @return false|string
     */
    public static function humanDate($time)
    {
        $timestamp = is_numeric($time) ? $time : strtotime($time);
        $dur = time() - $timestamp;
        if ($dur < 0) {
            return date('Y-m-d', $timestamp);
        } else {
            if ($dur < 60) {
                return $dur . '秒前';
            } else {
                if ($dur < 3600) {
                    return floor($dur / 60) . '分钟前';
                } else {
                    if ($dur < 86400) {
                        return floor($dur / 3600) . '小时前';
                    } else {
                        if ($dur < 2592000) { // 30天内
                            return floor($dur / 86400) . '天前';
                        } else {
                            return date('Y-m-d', $timestamp);;
                        }
                    }
                }
            }
        }
        return date('Y-m-d', $timestamp);
    }

    /**
     * 格式化文件大小
     * @param $file_size
     * @return string
     */
    public static function formatBytes($file_size): string
    {
        $size = sprintf("%u", $file_size);
        if ($size == 0) {
            return ("0 Bytes");
        }
        $size_name = array(" Bytes", " KB", " MB", " GB", " TB", " PB", " EB", " ZB", " YB");
        return round($size / pow(1024, ($i = floor(log($size, 1024)))), 2) . $size_name[$i];
    }

    /**
     * 数据库字符串转义
     * @param $var
     * @return false|string
     */
    public static function pdoQuote($var)
    {
        return Util::db()->getPdo()->quote($var);
    }

    /**
     * 检查表名是否合法
     * @param string $table
     * @return string
     * @throws BusinessException
     */
    public static function checkTableName(string $table): string
    {
        if (!preg_match('/^[a-zA-Z_0-9]+$/', $table)) {
            throw new BusinessException('表名不合法');
        }
        return $table;
    }

    /**
     * 变量或数组中的元素只能是字母数字下划线组合
     * @param $var
     * @return mixed
     * @throws BusinessException
     */
    public static function filterAlphaNum($var)
    {
        $vars = (array)$var;
        array_walk_recursive($vars, function ($item) {
            if (is_string($item) && !preg_match('/^[a-zA-Z_0-9]+$/', $item)) {
                throw new BusinessException('参数不合法');
            }
        });
        return $var;
    }

    /**
     * 变量或数组中的元素只能是字母数字
     * @param $var
     * @return mixed
     * @throws BusinessException
     */
    public static function filterNum($var)
    {
        $vars = (array)$var;
        array_walk_recursive($vars, function ($item) {
            if (is_string($item) && !preg_match('/^[0-9]+$/', $item)) {
                throw new BusinessException('参数不合法');
            }
        });
        return $var;
    }

    /**
     * @desc 检测是否是合法URL Path
     * @param $var
     * @return string
     * @throws BusinessException
     */
    public static function filterUrlPath($var): string
    {
        if (!is_string($var)) {
            throw new BusinessException('参数不合法，地址必须是一个字符串！');
        }

        if (strpos($var, 'https://') === 0 || strpos($var, 'http://') === 0) {
            if (!filter_var($var, FILTER_VALIDATE_URL)) {
                throw new BusinessException('参数不合法，不是合法的URL地址！');
            }
        } elseif (!preg_match('/^[a-zA-Z0-9_\-\/&?.]+$/', $var)) {
            throw new BusinessException('参数不合法，不是合法的Path！');
        }
        return $var;
    }

    /**
     * 检测是否是合法Path
     * @param $var
     * @return string
     * @throws BusinessException
     */
    public static function filterPath($var): string
    {
        if (!is_string($var) || !preg_match('/^[a-zA-Z0-9_\-\/]+$/', $var)) {
            throw new BusinessException('参数不合法');
        }
        return $var;
    }

    /**
     * 类转换为url path
     * @param $controller_class
     * @return false|string
     */
    static function controllerToUrlPath($controller_class)
    {
        $key = strtolower($controller_class);
        $action = '';
        if (strpos($key, '@')) {
            [$key, $action] = explode('@', $key, 2);
        }
        $prefix = 'plugin';
        $paths = explode('\\', $key);
        if (count($paths) < 2) {
            return false;
        }
        $base = '';
        if (strpos($key, "$prefix\\") === 0) {
            if (count($paths) < 4) {
                return false;
            }
            array_shift($paths);
            $plugin = array_shift($paths);
            $base = "/app/$plugin/";
        }
        array_shift($paths);
        foreach ($paths as $index => $path) {
            if ($path === 'controller') {
                unset($paths[$index]);
            }
        }
        $suffix = 'controller';
        $code = $base . implode('/', $paths);
        if (substr($code, -strlen($suffix)) === $suffix) {
            $code = substr($code, 0, -strlen($suffix));
        }
        return $action ? "$code/$action" : $code;
    }

    /**
     * 转换为驼峰
     * @param string $value
     * @return string
     */
    public static function camel(string $value): string
    {
        static $cache = [];
        $key = $value;

        if (isset($cache[$key])) {
            return $cache[$key];
        }

        $value = ucwords(str_replace(['-', '_'], ' ', $value));

        return $cache[$key] = str_replace(' ', '', $value);
    }

    /**
     * 转换为小驼峰
     * @param $value
     * @return string
     */
    public static function smCamel($value): string
    {
        return lcfirst(static::camel($value));
    }

    /**
     * 获取注释中第一行
     * @param $comment
     * @return false|mixed|string
     */
    public static function getCommentFirstLine($comment)
    {
        if ($comment === false) {
            return false;
        }
        foreach (explode("\n", $comment) as $str) {
            if ($s = trim($str, "*/\ \t\n\r\0\x0B")) {
                return $s;
            }
        }
        return $comment;
    }

    /**
     * 表单类型到插件的映射
     * @return \string[][]
     */
    public static function methodControlMap(): array
    {
        return [
            //method=>[控件]
            'integer' => ['InputNumber'],
            'string' => ['Input'],
            'text' => ['TextArea'],
            'date' => ['DatePicker'],
            'enum' => ['Select'],
            'float' => ['Input'],

            'tinyInteger' => ['InputNumber'],
            'smallInteger' => ['InputNumber'],
            'mediumInteger' => ['InputNumber'],
            'bigInteger' => ['InputNumber'],

            'unsignedInteger' => ['InputNumber'],
            'unsignedTinyInteger' => ['InputNumber'],
            'unsignedSmallInteger' => ['InputNumber'],
            'unsignedMediumInteger' => ['InputNumber'],
            'unsignedBigInteger' => ['InputNumber'],

            'decimal' => ['Input'],
            'double' => ['Input'],

            'mediumText' => ['TextArea'],
            'longText' => ['TextArea'],

            'dateTime' => ['DateTimePicker'],

            'time' => ['DateTimePicker'],
            'timestamp' => ['DateTimePicker'],

            'char' => ['Input'],

            'binary' => ['Input'],

            'json' => ['input']
        ];
    }

    /**
     * 数据库类型到插件的转换
     * @param $type
     * @return string
     */
    public static function typeToControl($type): string
    {
        if (stripos($type, 'int') !== false) {
            return 'inputNumber';
        }
        if (stripos($type, 'time') !== false || stripos($type, 'date') !== false) {
            return 'dateTimePicker';
        }
        if (stripos($type, 'text') !== false) {
            return 'textArea';
        }
        if ($type === 'enum') {
            return 'select';
        }
        return 'input';
    }

    /**
     * 数据库类型到表单类型的转换
     * @param $type
     * @param $unsigned
     * @return string
     */
    public static function typeToMethod($type, $unsigned = false)
    {
        if (stripos($type, 'int') !== false) {
            $type = str_replace('int', 'Integer', $type);
            return $unsigned ? "unsigned" . ucfirst($type) : lcfirst($type);
        }
        $map = [
            'int' => 'integer',
            'varchar' => 'string',
            'mediumtext' => 'mediumText',
            'longtext' => 'longText',
            'datetime' => 'dateTime',
        ];
        return $map[$type] ?? $type;
    }

    /**
     * 按表获取摘要
     * @param $table
     * @param null $section
     * @return array|mixed
     * @throws BusinessException
     */
    public static function getSchema($table, $section = null)
    {
        Util::checkTableName($table);
        $database = config('database.connections')['plugin.admin.mysql']['database'];
        $schema_raw = $section !== 'table' ? Util::db()->select("select * from information_schema.COLUMNS where TABLE_SCHEMA = '$database' and table_name = '$table' order by ORDINAL_POSITION") : [];
        $forms = [];
        $columns = [];
        foreach ($schema_raw as $item) {
            $field = $item->COLUMN_NAME;
            $columns[$field] = [
                'field' => $field,
                'type' => Util::typeToMethod($item->DATA_TYPE, (bool)strpos($item->COLUMN_TYPE, 'unsigned')),
                'comment' => $item->COLUMN_COMMENT,
                'default' => $item->COLUMN_DEFAULT,
                'length' => static::getLengthValue($item),
                'nullable' => $item->IS_NULLABLE !== 'NO',
                'primary_key' => $item->COLUMN_KEY === 'PRI',
                'auto_increment' => strpos($item->EXTRA, 'auto_increment') !== false
            ];

            $forms[$field] = [
                'field' => $field,
                'comment' => $item->COLUMN_COMMENT,
                'control' => static::typeToControl($item->DATA_TYPE),
                'form_show' => $item->COLUMN_KEY !== 'PRI',
                'list_show' => true,
                'enable_sort' => false,
                'searchable' => false,
                'search_type' => 'normal',
                'control_args' => '',
            ];
        }
        $table_schema = $section == 'table' || !$section ? Util::db()->select("SELECT TABLE_COMMENT FROM  information_schema.`TABLES` WHERE  TABLE_SCHEMA='$database' and TABLE_NAME='$table'") : [];
        $indexes = !$section || in_array($section, ['keys', 'table']) ? Util::db()->select("SHOW INDEX FROM `$table`") : [];
        $keys = [];
        $primary_key = [];
        foreach ($indexes as $index) {
            $key_name = $index->Key_name;
            if ($key_name == 'PRIMARY') {
                $primary_key[] = $index->Column_name;
                continue;
            }
            if (!isset($keys[$key_name])) {
                $keys[$key_name] = [
                    'name' => $key_name,
                    'columns' => [],
                    'type' => $index->Non_unique == 0 ? 'unique' : 'normal'
                ];
            }
            $keys[$key_name]['columns'][] = $index->Column_name;
        }

        $data = [
            'table' => ['name' => $table, 'comment' => $table_schema[0]->TABLE_COMMENT ?? '', 'primary_key' => $primary_key],
            'columns' => $columns,
            'forms' => $forms,
            'keys' => array_reverse($keys, true)
        ];

        $schema = Option::where('name', "table_form_schema_$table")->value('value');
        $form_schema_map = $schema ? json_decode($schema, true) : [];

        foreach ($data['forms'] as $field => $item) {
            if (isset($form_schema_map[$field])) {
                $data['forms'][$field] = $form_schema_map[$field];
            }
        }

        return $section ? $data[$section] : $data;
    }

    /**
     * 获取字段长度或默认值
     * @param $schema
     * @return mixed|string
     */
    public static function getLengthValue($schema)
    {
        $type = $schema->DATA_TYPE;
        if (in_array($type, ['float', 'decimal', 'double'])) {
            return "{$schema->NUMERIC_PRECISION},{$schema->NUMERIC_SCALE}";
        }
        if ($type === 'enum') {
            return implode(',', array_map(function ($item) {
                return trim($item, "'");
            }, explode(',', substr($schema->COLUMN_TYPE, 5, -1))));
        }
        if (in_array($type, ['varchar', 'text', 'char'])) {
            return $schema->CHARACTER_MAXIMUM_LENGTH;
        }
        if (in_array($type, ['time', 'datetime', 'timestamp'])) {
            return $schema->CHARACTER_MAXIMUM_LENGTH;
        }
        return '';
    }

    /**
     * 获取控件参数
     * @param $control
     * @param $control_args
     * @return array
     */
    public static function getControlProps($control, $control_args): array
    {
        if (!$control_args) {
            return [];
        }
        $control = strtolower($control);
        $props = [];
        $split = explode(';', $control_args);
        foreach ($split as $item) {
            $pos = strpos($item, ':');
            if ($pos === false) {
                continue;
            }
            $name = trim(substr($item, 0, $pos));
            $values = trim(substr($item, $pos + 1));
            // values = a:v,c:d
            $pos = strpos($values, ':');
            if ($pos !== false && strpos($values, "#") !== 0) {
                $options = explode(',', $values);
                $values = [];
                foreach ($options as $option) {
                    [$v, $n] = explode(':', $option);
                    if (in_array($control, ['select', 'selectmulti', 'treeselect', 'treemultiselect']) && $name == 'data') {
                        $values[] = ['value' => $v, 'name' => $n];
                    } else {
                        $values[$v] = $n;
                    }
                }
            }
            $props[$name] = $values;
        }
        return $props;

    }

    /**
     * 获取某个composer包的版本
     * @param string $package
     * @return mixed|string
     */
    public static function getPackageVersion(string $package)
    {
        $installed_php = base_path('vendor/composer/installed.php');
        if (is_file($installed_php)) {
            $packages = include $installed_php;
        }
        return substr($packages['versions'][$package]['version'] ?? 'unknown  ', 0, -2);
    }


    /**
     * Reload webman
     * @return bool
     */
    public static function reloadWebman()
    {
        if (function_exists('posix_kill')) {
            try {
                posix_kill(posix_getppid(), SIGUSR1);
                return true;
            } catch (Throwable $e) {
            }
        } else {
            Timer::add(1, function () {
                Worker::stopAll();
            });
        }
        return false;
    }

    /**
     * Pause file monitor
     * @return void
     */
    public static function pauseFileMonitor()
    {
        if (method_exists(Monitor::class, 'pause')) {
            Monitor::pause();
        }
    }

    /**
     * Resume file monitor
     * @return void
     */
    public static function resumeFileMonitor()
    {
        if (method_exists(Monitor::class, 'resume')) {
            Monitor::resume();
        }
    }


    /**
     * 重启请求
     *
     * @param string $url
     * @param array $data
     * @return array
     **/
    public static function rebootServerApi($url, $data)
    {
        $config = OptionService::getConfig('logo');
        if (empty($config['user_api_switch'])) {
            return [];
        }

        $api_url = $url;
        // 请求参数
        $postData = $data;

        $msg = '【服务端API】 ' . 'RebootServer' . ' ';
        $log = Log::channel('user_api');
        $log->info($msg . 'request ' . $api_url, $postData);

        // 初始化cURL
        $curl = curl_init();
        // 设置cURL选项
        curl_setopt($curl, CURLOPT_URL, $api_url);
        curl_setopt($curl, CURLOPT_POST, true);
        curl_setopt($curl, CURLOPT_POSTFIELDS, http_build_query($postData));
        curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($curl, CURLOPT_HTTPHEADER, [
            'Content-Type: application/x-www-form-urlencoded'
        ]);
        // 执行请求并获取响应
        $response = curl_exec($curl);
        // 检查错误
        if (curl_errno($curl)) {
            $log->info($msg . '请求错误: ' . curl_error($curl) . ' data ' . $api_url . ' ', []);
            return V(1, '请求错误: ' . curl_error($curl));
        }
        // 关闭cURL资源
        curl_close($curl);

        $result = json_decode($response, true);
        $log->info($msg . 'data ' . $api_url . ' ', $result);
        return $result;
    }

    /**
     * 节点请求
     *
     * @param string $function
     * @param string $url
     * @param array $data
     * @return array
     **/
    public static function userApi($function, $url, $data)
    {
        $config = OptionService::getConfig('logo');
        if (empty($config['user_api_switch'])) {
            return [];
        }

        // 接口地址
//        $url = 'http://' . $ip . ':'.$port . '/user/';
        $api_url = $url . $function;
        // 请求参数
        $postData = $data;

        $msg = '【服务端API】 ' . $function . ' ';
        $log = Log::channel('user_api');
        $log->info($msg . 'request ' . $api_url . ' ', $postData);

        // 初始化cURL
        $curl = curl_init();
        // 设置cURL选项
        curl_setopt($curl, CURLOPT_URL, $api_url);
        curl_setopt($curl, CURLOPT_POST, true);
        curl_setopt($curl, CURLOPT_POSTFIELDS, http_build_query($postData));
        curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($curl, CURLOPT_HTTPHEADER, [
            'Content-Type: application/x-www-form-urlencoded'
        ]);
        // 执行请求并获取响应
        $response = curl_exec($curl);
        // 检查错误
        if (curl_errno($curl)) {
            $log->info($msg . '请求错误: ' . curl_error($curl) . ' data ' . $api_url . ' ', []);
            return V(1, $msg . '请求错误: ' . curl_error($curl));
        }
        // 关闭cURL资源
        curl_close($curl);

        $result = json_decode($response, true);
        $log->info($msg . 'data ' . $api_url . ' ', $result);
        return $result;
    }

    /**
     * 批量节点请求
     *
     * @param string $function
     * @param array $data
     * @return array
     **/
    public static function batchUserApi($function, $data)
    {
        $config = OptionService::getConfig('logo');
        if (empty($config['user_api_switch'])) {
            return [];
        }

        $insertErrorData = [];
        $errorMsgData = [];
        if ($function == 'add') {
            foreach ($data as $key => $value) {
                $url = $value['url'];
                $apiData = $value;
                unset($apiData['url']);
                $result = self::userApi($function, $url, $apiData);
                if ($result['code'] != 200) {
                    $errorData = [];
                    $errorData['ip'] = $value['ip'] ?? '';
                    $errorData['port'] = $value['port'] ?? '';
                    $errorData['key'] = $value['key'];
                    $errorData['username'] = $value['username'];
                    $errorData['password'] = $value['password'];
                    $errorData['data'] = json_encode($value, JSON_UNESCAPED_UNICODE);
                    $errorData['error_info'] = $result['msg'];
                    unset($errorData['url']);
                    $insertErrorData[] = $errorData;
                    $errorMsgData[] = '服务器IP：' . $value['ip'] . ' add 错误';
                }
            }
        }
        if ($function == 'del') {
            foreach ($data as $key => $value) {
                $url = $value['url'];
                $apiData = [];
                $apiData['key'] = $value['key'];
                $apiData['username'] = $value['username'];
                $result = self::userApi($function, $url, $apiData);
                if ($result['code'] != 200) {
                    $errorData = $value;
                    $errorData['data'] = json_encode($value, JSON_UNESCAPED_UNICODE);
                    $errorData['error_info'] = $result['msg'];
                    unset($errorData['url']);
                    $insertErrorData[] = $errorData;
                    $errorMsgData[] = '服务器IP：' . $value['ip'] . ' del 错误';
                }
            }
            if ($insertErrorData) {
                self::db()->table('wa_v1_order_node_error')->insert($insertErrorData);
            }
        }
        return $errorMsgData;
    }

    /**
     * 验证
     *
     * @param string $controller
     * @param string $function
     * @param array $params
     * @return array
     **/
    public static function validateParams($controller, $function, $params)
    {
        if ($controller == 'v1-api') {
            switch ($function) {
                case 'createLink':
                    list($remark, $data) = array_values($params);
                    if (!$remark) {
                        return V(1, '请输入备注！');
                    }
                    if (!$data) {
                        return V(1, '推广链接权限数据不存在！');
                    }
                    break;
                case 'editUserExtend':
                    list($user_id, $data) = array_values($params);
                    if (!$user_id) {
                        return V(1, '会员参数错误！');
                    }
                    if (!$data) {
                        return V(1, '推广权限数据不存在！');
                    }
                    break;
                case 'recharge':
                    list($pay_type, $amount, $code) = array_values($params);
                    if (!array_key_exists($pay_type, CommonConstant::get_recharge_type_list())) {
                        return V(1, '请选择正确的支付方式！');
                    }
                    $code_data = [];
                    if ($pay_type == CommonConstant::PAYTYPE_CARD) {
                        $data = getLineBreak($code);
                        $code_data = array_unique($data);
                        if (!$code_data) {
                            return V(1, '请输入卡号！');
                        }
                    } else {
                        if (!$amount) {
                            return V(1, '请输入充值金额！');
                        }
                        if (!is_numeric($amount) || $amount < 1) {
                            return V(1, '充值金额不能小于1！');
                        }
                    }
                    $params['code_data'] = $code_data;
                    return V(0, 'success', $params);
                    break;
                case 'getRegionList':
                    list($line_id, $game_id) = array_values($params);
                    if (!$line_id) {
                        return V(1, '线路参数错误！');
                    }
                    if (!$game_id) {
                        return V(1, '游戏参数错误！');
                    }
                    break;
                case 'createOrder':
                    list($line_id, $game_id, $ip_segment, $duration, $custom_type, $account, $pass, $group, $remark, $port, $data) = array_values($params);

                    if (!$line_id) {
                        return V(1, '线路参数错误！');
                    }
                    if (!$game_id) {
                        return V(1, '游戏参数错误！');
                    }
                    if (!array_key_exists($duration, CommonConstant::get_duration_type_list())) {
                        return V(1, '请选择正确的时长！');
                    }
                    if (!array_key_exists($custom_type, CommonConstant::get_custom_type_list())) {
                        return V(1, '请选择正确的自定义账号！');
                    }
                    if ($custom_type == CommonConstant::DEFAULT_1) {
                        if (!$account) {
                            return V(1, '请输入账号！');
                        }
                        if (!$pass) {
                            return V(1, '请输入密码！');
                        }
                    }
                    if (!$data) {
                        return V(1, '请选择节点！');
                    }
                    foreach ($data as $value) {
                        if (empty($value['region_id'])) {
                            throw new BusinessException('节点参数错误！');
                        }
                        if (!is_numeric($value['number']) || $value['number'] < 1) {
                            throw new BusinessException('请输入有效数量！');
                        }
                    }
                    break;
                case 'getNodeRenewDurationList':
                    list($lineId) = array_values($params);
                    if (!$lineId) {
                        return V(1, '线路参数错误！');
                    }
                    break;
                case 'renew':
                    list($lineId, $duration, $ids) = array_values($params);
                    if (!$lineId) {
                        return V(1, '线路参数错误！');
                    }
                    if (!$duration) {
                        return V(1, '请选择续费时间！');
                    }
                    if (!array_key_exists($duration, CommonConstant::get_duration_sec_list())) {
                        return V(1, '请选择正确的续费时间！');
                    }
                    if (!$ids) {
                        return V(1, '节点参数错误！');
                    }
                    break;
                case 'getInvitationUserList':
                    list($username) = array_values($params);
                    if (!$username) {
                        return V(1, '请输入用户名！');
                    }
                    break;
                case 'transfer':
                    list($lineId, $toUserId, $ids) = array_values($params);
                    if (!$lineId) {
                        return V(1, '线路参数错误！');
                    }
                    if (!$toUserId) {
                        return V(1, '过户会员参数错误！');
                    }
                    if (!$ids) {
                        return V(1, '节点参数错误！');
                    }
                    break;
                case 'averageTime':
                    list($lineId, $date, $ids) = array_values($params);
                    if (!$lineId) {
                        return V(1, '线路参数错误！');
                    }
                    if (!$date) {
                        return V(1, '请选择平均日期！');
                    }
                    if (!$ids) {
                        return V(1, '节点参数错误！');
                    }
                    break;
                case 'updatePwd':
                    list($lineId, $type, $data, $password) = array_values($params);
                    if (!$lineId) {
                        return V(1, '线路参数错误！');
                    }
                    if (!$type) {
                        return V(1, '参数错误！');
                    }
                    if (!$data) {
                        return V(1, '节点参数错误！');
                    }
                    if ($type == 1 && !$password) {
                        return V(1, '请输入密码！');
                    }
                    break;
                case 'getGameListExchange':
                    list($lineId, $ids) = array_values($params);
                    if (!$lineId) {
                        return V(1, '线路参数错误！');
                    }
                    if (!$ids) {
                        return V(1, '节点参数错误！');
                    }
                    break;
                case 'exchange':
                    list($lineId, $type, $accountType, $account, $pass, $ids, $data, $gameId, $lineIdNew) = array_values($params);
                    if (!$lineId) {
                        return V(1, '线路参数错误！');
                    }
                    if (!in_array($type, [CommonConstant::DEFAULT_1, CommonConstant::DEFAULT_2, CommonConstant::DEFAULT_3, CommonConstant::DEFAULT_4])) {
                        return V(1, '类型参数错误！');
                    }
//                    if ($type == CommonConstant::DEFAULT_3) {
//                        if (!$lineId) {
//                            return V(1, '线路参数错误！');
//                        }
//                    }
                    if (!array_key_exists($accountType, CommonConstant::get_custom_type_list_exchange())) {
                        return V(1, '请选择正确的自定义账号！');
                    }
                    if ($accountType == CommonConstant::DEFAULT_1) {
                        if (!$account) {
                            return V(1, '请输入账号！');
                        }
                        if (!$pass) {
                            return V(1, '请输入密码！');
                        }
                    }
                    if (!$ids) {
                        return V(1, '节点参数错误！');
                    }
                    if ($type == CommonConstant::DEFAULT_3) {
                        if (!$data) {
                            return V(1, '请选择节点！');
                        }
                        foreach ($data as $value) {
                            if (empty($value['region_id'])) {
                                throw new BusinessException('请选择节点！');
                            }
                            if (!is_numeric($value['number']) || $value['number'] <= 0) {
                                throw new BusinessException('请输入有效数量！');
                            }
                        }
                        if (!$lineIdNew) {
                            return V(1, '更换线路参数错误！');
                        }
                    }
                    if ($type == CommonConstant::DEFAULT_4) {
                        if (!$gameId) {
                            return V(1, '请选择游戏！');
                        }
                    }
                    break;
                case 'renewAutoOpen':
                    list($ids, $status) = array_values($params);
                    if (!$ids) {
                        return V(1, '节点参数错误！');
                    }
                    if (!array_key_exists($status, CommonConstant::get_open_off_list())) {
                        return V(1, '状态错误！');
                    }
                    break;
                case 'bind':
                    list($ids) = array_values($params);
                    if (!$ids) {
                        return V(1, '节点参数错误！');
                    }
                    break;
                case 'createRefund':
                    // 申请退款
                    list($lineId, $ids) = array_values($params);
                    if (!$lineId) {
                        return V(1, '线路参数错误！');
                    }
                    if (!$ids) {
                        return V(1, '节点参数错误！');
                    }
                    break;
                case 'importMatchingData':
                    list($lineId, $isExpire, $content) = array_values($params);
                    if (!$lineId) {
                        return V(1, '线路参数错误！');
                    }
                    if (!$content) {
                        return V(1, '请输入导入数据！');
                    }

                    $data = getLineBreak($content);
                    $nodeData = [];
                    foreach ($data as $info) {
                        $nodeArr = explode('|', $info);
                        $nodeArr = getLineEmpty($nodeArr);

                        $nodeData[] = [
                            'ip' => $nodeArr[0] ?? '',
                            'port' => $nodeArr[1] ?? '',
                            'account' => $nodeArr[2] ?? '',
                            'pass' => $nodeArr[3] ?? '',
                            'expire_time' => $nodeArr[4] ?? '',
                        ];
                    }
                    if (!$nodeData) {
                        return V(1, '请输入有效的导入数据！');
                    }
                    $params['data'] = $nodeData;
                    return V(0, 'success', $params);
                    break;
                case 'createApi':
                    list($orderIds, $format, $line, $customLine, $output, $expireTime) = array_values($params);
                    if (!$orderIds) {
                        return V(1, '订单参数错误！');
                    }
                    if (!in_array($format, [CommonConstant::DEFAULT_1, CommonConstant::DEFAULT_2])) {
                        return V(1, '请选择正确的返回格式！');
                    }
                    if (!in_array($line, [CommonConstant::DEFAULT_1, CommonConstant::DEFAULT_2, CommonConstant::DEFAULT_3, CommonConstant::DEFAULT_4])) {
                        return V(1, '请选择正确的行分隔符！');
                    }
                    if ($line == CommonConstant::DEFAULT_4 && !$customLine) {
                        return V(1, '请输入自定义行分隔符！');
                    }
                    if (!in_array($output, [CommonConstant::DEFAULT_1, CommonConstant::DEFAULT_2])) {
                        return V(1, '请选择正确的输出样式定制！');
                    }
                    if (!in_array($format, [CommonConstant::DEFAULT_1, CommonConstant::DEFAULT_2])) {
                        return V(1, '请选择正确的返回格式！');
                    }
                    if ($expireTime && !is_numeric($expireTime)) {
                        return V(1, '请输入Token有效时间(天)！');
                    }
                    break;
            }
            return V(0, 'success');
        }
    }

    /**
     * 验证会员类型
     *
     * @param integer $user_id
     * @param array $admin
     * @return array
     **/
    public static function validateUserStatus($user_id, $admin)
    {
        if ($admin['user_status'] == CommonConstant::DEFAULT_1) {
            if (!$user_id) {
                return V(1, '会员参数错误！');
            }
            $user = (array)Util::db()->table('wa_admins')->where('id', $user_id)->first();
            if (!$user) {
                return V(1, '会员不存在或已删除！');
            }
        } else {
            $user = $admin;
        }
        return V(0, 'success', $user);
    }

    /**
     * 分布式锁
     *
     * @param string $key
     * @param integer $expire
     * @return bool
     **/
    public static function basicSetnx($key, $expire = 5)
    {
        $lockKey = 'myydl_lock:' . $key;
        $value = uniqid();
        $lock = Redis::setnx($lockKey, $value);
        if (!$lock) {
            // 设置失败 key已存在
            return false;
        }
        // 设置成功 key不存在 设置过期时间，避免死锁
        Redis::expire($lockKey, $expire);
        return true;
    }

    /**
     * 构建查询
     *
     * @param $searchField
     * @return array
     */
    public static function buildSearch($searchField)
    {
        try {
            $where = [];
            if (!empty($searchField)) {
                $like_words = 'name,title';
                $in_words = 'id,ids';
                foreach ($searchField as $key => $value) {
                    if (is_array($value) || mb_strlen($value) > 0) {
                        if (is_array($value) && !empty($value) && count($value) == 2) {
                            $where[] = [$key, 'between', [strtotime($value[0]), strtotime($value[1])]];
                        } else {
                            if (false !== strpos($like_words, $key)) {
                                $where[] = [$key, 'like', "%{$value}%"];
                            } elseif (false !== strpos($in_words, $key)) {
                                $where[] = [$key, 'in', $value];
                            } else {
                                $where[] = [$key, '=', $value];
                            }
                        }
                    }
                }
            }
            return $where;
        } catch (\Exception $e) {
            return [];
        }
    }

    /**
     * 构建批量更新
     */
    public static function buildBatchUpdate($tableName, $fields, $updateData)
    {
        $ids = array_keys($updateData);
        // 构建CASE语句和绑定参数
        $cases = [];
        $bindings = [];
        foreach ($fields as $field) {
            $caseSql = "CASE id ";
            foreach ($updateData as $id => $data) {
                $caseSql .= "WHEN ? THEN ? ";
                $bindings[] = $id;
                $bindings[] = $data[$field] ?? null;
            }
            $caseSql .= "END";
            $cases[$field] = $caseSql;
        }

        // 构建完整的SQL
        $setParts = [];
        foreach ($cases as $field => $caseSql) {
            $setParts[] = "{$field} = {$caseSql}";
        }

        $setClause = implode(', ', $setParts);
        $placeholders = implode(',', array_fill(0, count($ids), '?'));

        $sql = "UPDATE {$tableName} SET {$setClause} WHERE id IN ({$placeholders})";

        // 合并所有绑定参数
        $allBindings = array_merge($bindings, $ids);

        return [$sql, $allBindings];
    }

    /**
     * 获取服务器sk5端口
     *
     * @param mixed $item
     **/
    public static function getSk5Port($item)
    {
        // 服务器存在 多端口开启 sk5端口填写 替换
        if ($item->server) {
            if ($item->server->multi_port_status == CommonConstant::DEFAULT_1 && !empty($item->server->multi_port)) {
                $item->port = $item->server->multi_port;
                $item->multi_port = $item->server->multi_port;
            }
        } else {
            $item->port = '';
            $item->multi_port = '';
        }
    }

}
